﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

using XGameFrame.Collision;

namespace XGameFrame.Graphic
{
    public delegate void OnCollisionHandler(object o,CollisionEventArgs e);
    public class CoreGraphicElement
    {
        #region Events
        public static event OnCollisionHandler CollisionEvent;
        #endregion

        #region Fields Region
        private String name;
        private Texture2D texture;
        private Vector2 position;
        private Vector2 size;
        private Rectangle sourceRectangle;
        private Rectangle bounds;
        private Rectangle destRectangle;
        private Color Color = Color.White;
        private bool visible = true;
        private bool isHover;
        private bool enabled = true;
        private bool animationPaused = false;
        private List<CoreGraphicElement> collisionsList = new List<CoreGraphicElement>();
        private float scale = 1;
        private float rotation = 0;
        private Vector2 origin = new Vector2(0, 0);
        private float layerDepth = 0;
        private SpriteEffects spriteEffect;

        
        #endregion

        #region Properties Region
        /// <summary>
        /// Name given for the object 
        /// </summary>
        public String Name
        {
            get { return name; }
            set { name = value; }
        }
        public float Scale
        {
            get { return scale; }
            set 
            {
                scale = value;
                size.X *= scale;
                size.Y *= scale;
            }
        }
        public float Rotation
        {
            get { return rotation; }
            set { rotation = value; }
        }
        public Vector2 Origin
        {
            get { return origin; }
            set { origin = value; }
        }
        public float LayerDepth
        {
            get { return layerDepth; }
            set { layerDepth = value; }
        }
        public SpriteEffects SpriteEffect
        {
            get { return spriteEffect; }
            set { spriteEffect = value; }
        }
        /// <summary>
        /// Get the source rectangle of current frame on hole texture  or set it
        /// </summary>
        public Rectangle SourceRectangle
        {
            get { return sourceRectangle; }
            set { sourceRectangle = value; }
        }
        /// <summary>
        /// Get the destination rectanlge from the element
        /// </summary>
        public Rectangle DestRectangle
        {
            get { return destRectangle; }
            set { destRectangle = value; }
        }
        /// <summary>
        /// Get graphics texture or set it
        /// </summary>
        public Texture2D Texture
        {
            get { return texture; }
            set { texture = value; }
        }
        /// <summary>
        /// Get if Sprite actually is hovered or set it
        /// </summary>
        public bool IsHover
        {
            get { return isHover; }
            set { isHover = value; }
        }
        /// <summary>
        /// Get the rectangle from element or set it
        /// </summary>
        public Rectangle Bounds
        {
            get { return bounds; }
            set { bounds = value; }
        }
        /// <summary>
        /// Get if sprites animation actually is paused or set it
        /// </summary>
        public bool AnimationPaused
        {
            get { return animationPaused; }
            set { animationPaused = value; }
        }

        /// <summary>
        /// Get if sprites actually is enabled or set it
        /// </summary>
        public bool Enabled
        {
            get { return enabled; }
            set { enabled = value; }
        }
        /// <summary>
        /// Get if sprites actually is visible or set it
        /// </summary>
        public bool Visible
        {
            get { return visible; }
            set { visible = value; }
        }
        
        /// <summary>
        /// Get graphics Position or set it
        /// </summary>
        public Vector2 Position
        {
            get { return position; }
            set
            {
                position = value;
                position.Y = (int)position.Y;
            }
        }

        /// <summary>
        /// Get graphics Size or set it
        /// </summary>
        public Vector2 Size
        {
            get { return size; }
            set { size = value; }
        }
        public Vector2 TopLeft
        {
            get { return new Vector2(Bounds.Left, this.Bounds.Top); }
        }

        public Vector2 TopRight
        {
            get { return new Vector2(this.Bounds.Right, this.Bounds.Top); }
        }

        public Vector2 TopCenter
        {
            get { return new Vector2(this.Bounds.Left + (this.Size.X / 2), this.Bounds.Top); }
        }

        public Vector2 BottomLeft
        {
            get { return new Vector2(this.Bounds.Left, this.Bounds.Bottom); }
        }

        public Vector2 BottomRight
        {
            get { return new Vector2(this.Bounds.Right, this.Bounds.Bottom); }
        }

        public Vector2 BottomCenter
        {
            get { return new Vector2(this.Bounds.Left + (this.Size.X / 2), this.Bounds.Bottom); }
        }

        public Vector2 LeftCenter
        {
            get { return new Vector2(this.Bounds.Left, this.Bounds.Top + (this.Size.Y / 2)); }
        }

        public Vector2 RightCenter
        {
            get { return new Vector2(this.Bounds.Right, this.Bounds.Top + (this.Size.Y / 2)); }
        }

        public Vector2 Center
        {
            get { return new Vector2(this.Bounds.Left + (this.Size.X / 2), this.Bounds.Top + (this.Size.Y / 2)); }
        }
        #endregion

        #region contructor
        public CoreGraphicElement(Texture2D pTexture,Vector2 pPosition)
        {
            Texture = pTexture;
            Size = new Vector2((float)Texture.Width, (float)Texture.Height);
            Position = new Vector2((float)pPosition.X, (float)pPosition.Y);
            Bounds = new Rectangle((int)Position.X, (int)Position.Y, (int)Size.X, (int)Size.Y);
            CollisionEvent += new OnCollisionHandler(this.OnCollision);
            //UpdateBoundPositions();
        }
        /// <summary>
        /// Constructor without apply Size, Texture, Bounds
        /// inherited classes have to do this
        /// </summary>
        /// <param name="pPosition">Position where the element will be shown</param>
        public CoreGraphicElement(Vector2 pPosition)
        {
            Position = pPosition;
            CollisionEvent += new OnCollisionHandler(this.OnCollision);
        }

        #endregion

        #region Methods


        
        /// <summary>
        /// Check a Collision between the two Elements
        /// </summary>
        /// <param name="pGraphicElement1">first CollisionElement normally this</param>
        /// <param name="pGraphicElement2">sec CollisionElement</param>
        /// <returns></returns>
        private Boolean CheckCollision(CoreGraphicElement pGraphicElement1, CoreGraphicElement pGraphicElement2)
        {
            return CollisionHandler.CheckOpaqueCollison(pGraphicElement1, pGraphicElement2);
        }
        /// <summary>
        /// Add a CollisionElement and check if a collision takes place
        /// </summary>
        /// <param name="pGraphicCollision">the checked CollisionElement</param>
        public void AddCollisionElement(CoreGraphicElement pGraphicCollision)
        {
            this.collisionsList.Add(pGraphicCollision);
            
        }
        /// <summary>
        /// check all Collisions
        /// </summary>
        public void CheckAllCollisions()
        {
            if (collisionsList.Count == 0)
                return;
            foreach (CoreGraphicElement _GraphicElement in collisionsList)
            {
                bool Collision = CheckCollision(this, _GraphicElement);
                if (Collision)
                {
                    CollisionEventArgs e = new CollisionEventArgs(_GraphicElement);
                    throwCollision(e);
                }

            }

        }
        #endregion


        #region abstract Methods


        #endregion

        #region event Method


        public void throwCollision(CollisionEventArgs e)
        {
            if (CollisionEvent != null)
                CollisionEvent(this, e);
        }

        public void OnCollision(object o, CollisionEventArgs e)
        {
            
        }    
        

        #endregion

    }
}
